namespace NFTRedit
{
    using System;
    using System.Drawing;
    using System.IO;

    public class CGLPChunk
    {
        private static Bitmap backDot = new Bitmap(1, 1);
        private static Color backgroundColor = Color.Transparent;
        private static readonly uint headerSize = 0x10;
        private static readonly uint MAGIC = 0x43474c50;
        private byte mBitsPerPixel;
        private ushort mBytesPerTile;
        private static Bitmap[] mDots;
        private byte mMaxHeight;
        private byte mMaxWidth;
        private byte mOrientation;
        private uint mSize;
        private Bitmap[] mTiles;
        private byte mUnknown1;
        private byte mUnknown2;
        private uint numTiles;

        static CGLPChunk()
        {
            backDot.SetPixel(0, 0, backgroundColor);
        }

        public CGLPChunk(BinaryReader reader)
        {
            this.Load(reader);
        }

        public void CorrectTileCount(int count)
        {
            Bitmap[] mTiles = this.mTiles;
            this.mTiles = new Bitmap[count];
            for (int i = 0; i < count; i++)
            {
                this.mTiles[i] = mTiles[i];
            }
            for (int j = count; j < mTiles.Length; j++)
            {
                mTiles[j].Dispose();
            }
        }

        private byte getIndex(Color c)
        {
            for (byte i = 0; i < this.Dots.Length; i = (byte) (i + 1))
            {
                if (c.A == this.Dots[i].GetPixel(0, 0).A)
                {
                    return i;
                }
            }
            return 0;
        }

        private void Load(BinaryReader reader)
        {
            this.ReadHeader(reader);
            int num = (int) Math.Pow(2.0, (double) this.mBitsPerPixel);
            mDots = new Bitmap[num];
            for (int i = 0; i < num; i++)
            {
                int alpha = (0xff * i) / (num - 1);
                this.Dots[i] = new Bitmap(1, 1);
                this.Dots[i].SetPixel(0, 0, Color.FromArgb(alpha, 0, 0, 0));
            }
            this.ReadBody(reader);
        }

        private void ReadBody(BinaryReader reader)
        {
            this.numTiles = (this.mSize - headerSize) / this.mBytesPerTile;
            this.mTiles = new Bitmap[this.numTiles];
            byte num = reader.ReadByte();
            for (int i = 0; i < this.numTiles; i++)
            {
                this.mTiles[i] = new Bitmap(this.mMaxWidth, this.mMaxHeight);
                Graphics graphics = Graphics.FromImage(this.mTiles[i]);
                graphics.Clear(backgroundColor);
                int num3 = 0;
                int x = 0;
                int y = 0;
                ushort num6 = 0x80;
                while ((num3 < this.mBytesPerTile) && (y < this.mMaxHeight))
                {
                    byte num7 = (byte) Math.Pow(2.0, (double) (this.mBitsPerPixel - 1));
                    byte index = 0;
                    while (num7 > 0)
                    {
                        if ((num & num6) > 0)
                        {
                            index = (byte) (index + num7);
                        }
                        num6 = (ushort) (num6 >> 1);
                        if (num6 == 0)
                        {
                            num6 = 0x80;
                            num3++;
                            num = reader.ReadByte();
                        }
                        num7 = (byte) (num7 >> 1);
                    }
                    if (index > 0)
                    {
                        graphics.DrawImageUnscaled(this.Dots[index], x, y);
                    }
                    x++;
                    if (x >= this.mMaxWidth)
                    {
                        x = 0;
                        y++;
                    }
                }
                while (num3 < this.mBytesPerTile)
                {
                    num = reader.ReadByte();
                    num3++;
                }
                graphics.Dispose();
            }
            Stream baseStream = reader.BaseStream;
            baseStream.Position -= 1L;
            for (int j = (int) (3L - ((reader.BaseStream.Position - 1L) % 4L)); j > 0; j--)
            {
                reader.ReadByte();
            }
        }

        private void ReadHeader(BinaryReader reader)
        {
            if (reader.ReadUInt32() != MAGIC)
            {
                throw new FormatException("File is not NFTR format.");
            }
            this.mSize = reader.ReadUInt32();
            this.mMaxWidth = reader.ReadByte();
            this.mMaxHeight = reader.ReadByte();
            this.mBytesPerTile = reader.ReadUInt16();
            this.mUnknown1 = reader.ReadByte();
            this.mUnknown2 = reader.ReadByte();
            this.mBitsPerPixel = reader.ReadByte();
            this.mOrientation = reader.ReadByte();
        }

        public void RecalculateSize()
        {
            uint num = headerSize + (this.numTiles * this.mBytesPerTile);
            while ((num % 4) != 0)
            {
                num++;
            }
            this.mSize = num;
        }

        public void ResizeTiles(byte w, byte h)
        {
            this.mBytesPerTile = (ushort) Math.Ceiling((double) (((double) ((w * h) * this.mBitsPerPixel)) / 8.0));
            int y = h - this.mMaxHeight;
            for (int i = 0; i < this.Tiles.Length; i++)
            {
                Bitmap image = new Bitmap(w, h);
                Graphics graphics = Graphics.FromImage(image);
                graphics.Clear(Color.Transparent);
                graphics.DrawImageUnscaled(this.Tiles[i], 0, y);
                graphics.Dispose();
                this.Tiles[i].Dispose();
                this.Tiles[i] = image;
            }
            this.mMaxWidth = w;
            this.mMaxHeight = h;
            this.RecalculateSize();
        }

        public void Save(BinaryWriter writer)
        {
            this.WriteHeader(writer);
            this.WriteBody(writer);
        }

        private void WriteBody(BinaryWriter writer)
        {
            for (int i = 0; i < this.mTiles.Length; i++)
            {
                short num = (byte) (8 - this.mBitsPerPixel);
                byte num3 = 0;
                int x = 0;
                int y = 0;
                while (y < this.mMaxHeight)
                {
                    Color pixel = this.mTiles[i].GetPixel(x, y);
                    byte num6 = this.getIndex(pixel);
                    if (num >= 0)
                    {
                        num3 = (byte) (num3 | ((byte) (num6 << num)));
                    }
                    else
                    {
                        ushort num7 = (ushort) (num6 << (8 + num));
                        num3 = (byte) (num3 | ((byte) (num7 >> 8)));
                        writer.Write(num3);
                        num3 = (byte) (num7 & 0xff);
                        num = (short) (num + 8);
                    }
                    if (num == 0)
                    {
                        num = (byte) (8 - this.mBitsPerPixel);
                        writer.Write(num3);
                        num3 = 0;
                    }
                    else
                    {
                        num = (short) (num - this.mBitsPerPixel);
                    }
                    x++;
                    if (x >= this.mMaxWidth)
                    {
                        x = 0;
                        y++;
                    }
                }
                if (num != (8 - this.mBitsPerPixel))
                {
                    writer.Write(num3);
                }
            }
            writer.Flush();
            for (int j = (int) (3L - ((writer.BaseStream.Position - 1L) % 4L)); j > 0; j--)
            {
                writer.Write((byte) 0);
            }
        }

        private void WriteHeader(BinaryWriter writer)
        {
            writer.Write(MAGIC);
            writer.Write(this.mSize);
            writer.Write(this.mMaxWidth);
            writer.Write(this.mMaxHeight);
            writer.Write(this.mBytesPerTile);
            writer.Write(this.mUnknown1);
            writer.Write(this.mUnknown2);
            writer.Write(this.mBitsPerPixel);
            writer.Write(this.mOrientation);
        }

        public byte BPP
        {
            get
            {
                return this.mBitsPerPixel;
            }
        }

        public Bitmap[] Dots
        {
            get
            {
                return mDots;
            }
        }

        public int Length
        {
            get
            {
                return (int) this.mSize;
            }
        }

        public byte MaxHeight
        {
            get
            {
                return this.mMaxHeight;
            }
        }

        public byte MaxWidth
        {
            get
            {
                return this.mMaxWidth;
            }
        }

        public byte Orientation
        {
            get
            {
                return this.mOrientation;
            }
        }

        public Bitmap[] Tiles
        {
            get
            {
                return this.mTiles;
            }
        }
    }
}

